﻿/*******************************************************************************
 * Copyright (c) 2010-2011 Robert Fraser                                       *
 *                                                                             *
 * Permission is hereby granted, free of charge, to any person obtaining a     *
 * copy of this software and associated documentation files (the "Software"),  *
 * to deal in the Software without restriction, including without limitation   *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
 * and/or sell copies of the Software, and to permit persons to whom the       *
 * Software is furnished to do so, subject to the following conditions:        *
 *                                                                             *
 *   - The above copyright notice and this permission notice shall be included *
 *     in all copies or substantial portions of the Software.                  *
 *                                                                             *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
 * DEALINGS IN THE SOFTWARE.                                                   *
 *******************************************************************************/

using System;

namespace zeal.core
{
    public struct TextureType : IEquatable<TextureType>
    {
        private readonly TextureDataType _dataType;
        private readonly TexturePixelType _pixelType;

        public TextureType(TextureDataType dataType, TexturePixelType pixelType)
        {
            _dataType = dataType;
            _pixelType = pixelType;
        }

        public TextureDataType dataType { get { return _dataType; } }
        public TexturePixelType pixelType { get { return _pixelType; } }

        public override string ToString() { return string.Format(getFormatString(_dataType), getTypeString(_pixelType)); }

        public bool isVariable { get { return _pixelType == TexturePixelType.VARIABLE; } }

        public static bool canConvert(TexturePixelType t1, TexturePixelType t2) { return match(t1, t2).HasValue; }
        public static TexturePixelType? match(TexturePixelType t1, TexturePixelType t2)
        {
            if (t1 == t2)                             { return t1; }
            else if (t1 == TexturePixelType.VARIABLE) { return t2; }
            else if (t2 == TexturePixelType.VARIABLE) { return t1; }
            else                                      { return null; }
        }

        public static bool canConvert(TextureType t1, TextureType t2) { return match(t1, t2).HasValue; }
        public static TextureType? match(TextureType t1, TextureType t2)
        {
            if(t1.dataType != t2.dataType)
                return null;
            TexturePixelType? pType = match(t1.pixelType, t2.pixelType);
            return pType.HasValue ? new TextureType(t1.dataType, pType.Value) : (TextureType?) null;
        }
        
        private static string getFormatString(TextureDataType type)
        {
            switch(type)
            {
                case TextureDataType.PIXEL:     return "{0}";
                case TextureDataType.TEXTURE2D: return "Texture2D<{0}>";
                default:
                    throw new ArgumentOutOfRangeException("type");
            }
        }

        private static string getTypeString(TexturePixelType type)
        {
            switch (type)
            {
                case TexturePixelType.VARIABLE: return "?";
                case TexturePixelType.FLOAT:    return "float";
                case TexturePixelType.VECTOR2:  return "float2";
                case TexturePixelType.ARGB:     return "color";
                default:
                    throw new ArgumentOutOfRangeException("type");
            }
        }

        public static bool operator ==(TextureType left, TextureType right) { return left.Equals(right); }
        public static bool operator !=(TextureType left, TextureType right) { return !left.Equals(right); }
        public override int GetHashCode() { unchecked { return ((int) _dataType) | (((int) _pixelType) << 16); } }
        public bool Equals(TextureType other) { return other.dataType == dataType && other.pixelType == pixelType; }
        public override bool Equals(object obj)
        {
            if(ReferenceEquals(null, obj)) return false;
            if(obj.GetType() != typeof(TextureType)) return false;
            return Equals((TextureType) obj);
        }
    }

    // ReSharper disable InconsistentNaming
    public enum TextureDataType : ushort
    {
        PIXEL,
        TEXTURE2D,
        NUM_DATA_TYPES,
    }
    // ReSharper restore InconsistentNaming

    public enum TexturePixelType : ushort
    {
        VARIABLE,
        FLOAT,
        VECTOR2,
        ARGB,
        NUM_PIXEL_TYPES,
    }
}